﻿Option Explicit On
Option Strict On

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Text
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Imports System.Windows.Forms.Design

''' <summary>
''' Designer class for the LED Meter
''' </summary>
''' <remarks></remarks>
Friend Class LEDMeterDesigner
    Inherits Windows.Forms.Design.ControlDesigner

    Protected Overrides Sub PostFilterProperties(ByVal properties As System.Collections.IDictionary)

        If properties Is Nothing Then
            Throw New ArgumentNullException("properties")
        End If

        properties.Remove("AccessibleDescription")
        properties.Remove("AccessibleName")
        properties.Remove("AccessibleRole")
        properties.Remove("BackgroundImage")
        properties.Remove("BorderStyle")
        properties.Remove("Cursor")
        properties.Remove("RightToLeft")
        properties.Remove("UseWaitCursor")
        properties.Remove("AllowDrop")
        properties.Remove("AutoValidate")
        properties.Remove("ContextMenuStrip")
        properties.Remove("Enabled")
        properties.Remove("ImeMode")
        properties.Remove("TabStop")
        properties.Remove("ApplicationSettings")
        properties.Remove("DataBindings")
        properties.Remove("Tag")
        properties.Remove("GenerateMember")
        properties.Remove("Locked")
        properties.Remove("CausesValidation")
        properties.Remove("Anchor")
        properties.Remove("AutoSize")
        properties.Remove("AutoSizeMode")
        properties.Remove("Dock")
        properties.Remove("Margin")
        properties.Remove("MaximumSize")
        properties.Remove("MinimumSize")
        properties.Remove("Padding")
        properties.Remove("DockPadding")
        properties.Remove("AutoScrollMargin")
        properties.Remove("AutoScrollMinSize")
        properties.Remove("AutoScroll")
        properties.Remove("ForeColor")
        properties.Remove("Text")

    End Sub

End Class

<Designer(GetType(LEDMeterDesigner))> _
Friend Class LEDMeter
    Inherits UserControl

#Region " Enums "

    Friend Enum MeterScaleEnum
        Analog
        Log10
    End Enum

#End Region

#Region " Private Members "

    Private m_CurrentLevel As Integer
    Private m_PeakLevel As Integer
    Private m_LedCount1 As Integer = 6
    Private m_LedCount2 As Integer = 6
    Private m_LedCount3 As Integer = 4
    Private m_calcValue As Integer
    Private m_calcPeak As Integer
    Private m_LedColorOn1 As Color = Color.LimeGreen
    Private m_LedColorOn2 As Color = Color.Yellow
    Private m_LedColorOn3 As Color = Color.Red
    Private m_LedColorOff1 As Color = Color.DarkGreen
    Private m_LedColorOff2 As Color = Color.Olive
    Private m_LedColorOff3 As Color = Color.Maroon
    Private m_Min As Integer = 0
    Private m_Max As Integer = 65535
    Private m_PeakHoldTime As Integer = 1000
    Private m_ShowPeak As Boolean = True

    'Private m_DegLow As Double = Math.PI * 0.8
    'Private m_DegHigh As Double = Math.PI * 1.2

    Protected m_PeakTimer As Timer
    Private m_Led As Size = New Size(6, 14)
    Private m_LedSpacing As Integer = 3

    Private m_FormType As MeterScaleEnum = MeterScaleEnum.Log10

#End Region

#Region " Constructor "

    ''' <summary>
    ''' Default Constructor 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()

        Me.Name = "LEDMeter"
        CalcSize()
        Me.SetStyle(ControlStyles.DoubleBuffer, True)
        Me.SetStyle(ControlStyles.UserPaint, True)
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        m_PeakTimer = New Timer()
        m_PeakTimer.Interval = m_PeakHoldTime
        m_PeakTimer.Enabled = False
        AddHandler m_PeakTimer.Tick, New EventHandler(AddressOf PeakTimer_Tick)

    End Sub

#End Region

#Region " Public Properties "

    <Category("LED Meter")> _
    <Description("Display value in analog or logarithmic scale")> _
    Public Property MeterScale As MeterScaleEnum
        Get
            Return m_FormType
        End Get
        Set(ByVal value As MeterScaleEnum)
            m_FormType = value
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("Led size (1 to 72 pixels)")> _
    Public Property LedSize As Size
        Get
            Return m_Led
        End Get
        Set(ByVal value As Size)
            If (value.Height < 1) Then
                m_Led.Height = 1
            ElseIf (value.Height > 72) Then
                m_Led.Height = 72
            Else
                m_Led.Height = value.Height
            End If

            If (value.Width < 1) Then
                m_Led.Width = 1
            ElseIf (value.Width > 72) Then
                m_Led.Width = 72
            Else
                m_Led.Width = value.Width
            End If

            CalcSize()
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("Led spacing (0 to 72 pixels)")> _
    Public Property LedSpace As Integer
        Get
            Return m_LedSpacing
        End Get
        Set(ByVal value As Integer)
            If value < 0 Then
                m_LedSpacing = 0
            ElseIf value > 72 Then
                m_LedSpacing = 72
            Else
                m_LedSpacing = value
            End If
            CalcSize()
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("Max value from total LedCount to 65535")> _
    Public Property LevelMax As Integer
        Get
            Return m_Max
        End Get
        Set(ByVal value As Integer)
            If (value < (Led1Count + Led2Count + Led3Count)) Then
                m_Max = (Led1Count + Led2Count + Led3Count)
            ElseIf (value > 65535) Then
                m_Max = 65535
            Else
                m_Max = value
            End If

            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("The level shown (between Min and Max)")> _
    Public Property Level As Integer
        Get
            Return m_CurrentLevel
        End Get
        Set(ByVal value As Integer)
            If Not value = m_CurrentLevel Then
                If (value < m_Min) Then
                    m_CurrentLevel = m_Min
                ElseIf (value > m_Max) Then
                    m_CurrentLevel = m_Max
                Else
                    m_CurrentLevel = value
                End If

                If ((m_CurrentLevel > m_PeakLevel) And (m_ShowPeak)) Then
                    m_PeakLevel = m_CurrentLevel
                    m_PeakTimer.Stop()
                    m_PeakTimer.Start()
                End If
                Me.Invalidate()
            End If
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("How many mS to hold peak indicator (50 to 10000mS)")> _
    Public Property Peakms As Integer
        Get
            Return m_PeakHoldTime
        End Get
        Set(ByVal value As Integer)
            If (value < 50) Then
                m_PeakHoldTime = 50
            ElseIf (value > 10000) Then
                m_PeakHoldTime = 10000
            Else
                m_PeakHoldTime = value
            End If

            m_PeakTimer.Interval = m_PeakHoldTime
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("Use peak indicator")> _
    Public Property PeakHold As Boolean
        Get
            Return m_ShowPeak
        End Get
        Set(ByVal value As Boolean)
            m_ShowPeak = value
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("Number of Leds in first area (0 to 32, default 6) Total Led count must be at least 1")> _
    Public Property Led1Count As Integer
        Get
            Return m_LedCount1
        End Get
        Set(ByVal value As Integer)
            If (value < 0) Then
                m_LedCount1 = 0
            ElseIf (value > 32) Then
                m_LedCount1 = 32
            Else
                m_LedCount1 = value
            End If
            If ((m_LedCount1 + m_LedCount2 + m_LedCount3) < 1) Then m_LedCount1 = 1
            CalcSize()
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("Number of Leds in middle area (0 to 32, default 6) Total Led count must be at least 1")> _
    Public Property Led2Count As Integer
        Get
            Return m_LedCount2
        End Get
        Set(ByVal value As Integer)
            If (value < 0) Then
                m_LedCount2 = 0
            ElseIf (value > 32) Then
                m_LedCount2 = 32
            Else
                m_LedCount2 = value
            End If

            If ((m_LedCount1 + m_LedCount2 + m_LedCount3) < 1) Then m_LedCount2 = 1
            CalcSize()
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter")> _
    <Description("Number of Leds in last area (0 to 32, default 4) Total Led count must be at least 1")> _
    Public Property Led3Count As Integer
        Get
            Return m_LedCount3
        End Get
        Set(ByVal value As Integer)
            If (value < 0) Then
                m_LedCount3 = 0
            ElseIf (value > 32) Then
                m_LedCount3 = 32
            Else
                m_LedCount3 = value
            End If

            If ((m_LedCount1 + m_LedCount2 + m_LedCount3) < 1) Then m_LedCount3 = 1
            CalcSize()
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter - Colors")> _
    <Description("Color of Leds in first area (Led on)")> _
    Public Property Led1ColorOn As Color
        Get
            Return m_LedColorOn1
        End Get
        Set(ByVal value As Color)
            m_LedColorOn1 = value
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter - Colors")> _
    <Description("Color of Leds in middle area (Led on)")> _
    Public Property Led2ColorOn As Color
        Get
            Return m_LedColorOn2
        End Get
        Set(ByVal value As Color)
            m_LedColorOn2 = value
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter - Colors")> _
    <Description("Color of Leds in last area (Led on)")> _
    Public Property Led3ColorOn As Color
        Get
            Return m_LedColorOn3
        End Get
        Set(ByVal value As Color)
            m_LedColorOn3 = value
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter - Colors")> _
    <Description("Color of Leds in first area (Led off)")> _
    Public Property Led1ColorOff As Color
        Get
            Return m_LedColorOff1
        End Get
        Set(ByVal value As Color)
            m_LedColorOff1 = value
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter - Colors")> _
    <Description("Color of Leds in middle area (Led off)")> _
    Public Property Led2ColorOff As Color
        Get
            Return m_LedColorOff2
        End Get
        Set(ByVal value As Color)
            m_LedColorOff2 = value
            Me.Invalidate()
        End Set
    End Property

    <Category("LED Meter - Colors")> _
    <Description("Color of Leds in last area (Led off)")> _
    Public Property Led3ColorOff As Color
        Get
            Return m_LedColorOff3
        End Get
        Set(ByVal value As Color)
            m_LedColorOff3 = value
            Me.Invalidate()
        End Set
    End Property

#End Region

#Region " Private Methods "

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        'Validate Parameters
        If e Is Nothing Then
            Throw New ArgumentNullException("e")
        End If

        Dim g As Graphics = e.Graphics
        DrawBorder(g)
        DrawLeds(g)
    End Sub

    Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
        CalcSize()
        MyBase.OnResize(e)
        Me.Invalidate()
    End Sub

    Private Sub PeakTimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
        m_PeakTimer.Stop()
        m_PeakLevel = m_CurrentLevel
        Me.Invalidate()
        m_PeakTimer.Start()
    End Sub

    Private Sub CalcSize()
        Me.Size = New Size((m_LedCount1 + m_LedCount2 + m_LedCount3) * (m_Led.Width + m_LedSpacing) + m_LedSpacing, m_Led.Height + m_LedSpacing * 2)
    End Sub

    Private Sub DrawLeds(ByVal g As Graphics)
        If m_FormType = MeterScaleEnum.Log10 Then
            m_calcValue = CInt(Math.Log10(CDbl(m_CurrentLevel) / (m_Max / 10) + 1) * (m_LedCount1 + m_LedCount2 + m_LedCount3))
            If (m_ShowPeak) Then m_calcPeak = CInt(Math.Log10(CDbl(m_PeakLevel) / (m_Max / 10) + 1) * (m_LedCount1 + m_LedCount2 + m_LedCount3))
        End If

        If m_FormType = MeterScaleEnum.Analog Then
            m_calcValue = CInt((CDbl(m_CurrentLevel) / m_Max) * (m_LedCount1 + m_LedCount2 + m_LedCount3)) '+ 0.5)
            If (m_ShowPeak) Then m_calcPeak = CInt((CDbl(m_PeakLevel) / m_Max) * (m_LedCount1 + m_LedCount2 + m_LedCount3) + 0.5)
        End If


        For i As Integer = 0 To (m_LedCount1 + m_LedCount2 + m_LedCount3) - 1

            Dim current As Rectangle = New Rectangle(Me.ClientRectangle.X + (i * (m_Led.Width + m_LedSpacing)) + m_LedSpacing, Me.ClientRectangle.Y + m_LedSpacing, m_Led.Width, m_Led.Height)

            If ((i) < m_calcValue Or (((i + 1) = m_calcPeak) And m_ShowPeak)) Then
                If i < m_LedCount1 Then
                    Using LedGradientBrush As New LinearGradientBrush(New Point(current.Left, current.Top), New Point(current.Right + 5, current.Bottom), Color.FromArgb(63, 255, 63), Color.FromArgb(0, 60, 0))
                        g.FillRectangle(LedGradientBrush, current)
                    End Using
                ElseIf (i < (m_LedCount1 + m_LedCount2)) Then
                    Using Brush As New SolidBrush(m_LedColorOn2)
                        g.FillRectangle(Brush, current)
                    End Using
                Else
                    Using LedGradientBrush As New LinearGradientBrush(New Point(current.Left, current.Top), New Point(current.Right + 5, current.Bottom), Color.FromArgb(255, 63, 63), Color.FromArgb(60, 0, 0))
                        g.FillRectangle(LedGradientBrush, current)
                    End Using
                End If
            Else
                If i < m_LedCount1 Then
                    Using Brush As New SolidBrush(m_LedColorOff1)
                        g.FillRectangle(Brush, current)
                    End Using
                ElseIf (i < (m_LedCount1 + m_LedCount2)) Then
                    Using Brush As New SolidBrush(m_LedColorOff2)
                        g.FillRectangle(Brush, current)
                    End Using
                Else
                    Using Brush As New SolidBrush(m_LedColorOff3)
                        g.FillRectangle(Brush, current)
                    End Using
                End If
            End If

        Next
    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="g"></param>
    ''' <remarks></remarks>
    Private Sub DrawBorder(ByVal g As Graphics)
        Dim Border As Rectangle = New Rectangle(Me.ClientRectangle.X, Me.ClientRectangle.Y, Me.ClientRectangle.Width, Me.ClientRectangle.Height)
        Using Brush As New SolidBrush(Me.BackColor)
            g.FillRectangle(Brush, Border)
        End Using
    End Sub

#End Region

End Class
